﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Drawing;
using LowLevelGraphics.Types.Interval;

namespace LowLevelGraphics.Filter
{
    /// <summary>
    /// Tries to find only the given colors.
    /// This is a color filter
    /// All pixels will be set to the replacement color
    /// if their color matches one of the color in m_aColor
    /// </summary>
    public class FindOnly : BaseImageFilter
    {
        protected IEnumerable<Color> m_aColor = null;
        protected Color m_ColorToReplaceWith = Color.Transparent;

        protected ByteInterval m_ByteIntervalR = null;
        protected ByteInterval m_ByteIntervalG = null;
        protected ByteInterval m_ByteIntervalB = null;

        /// <summary>
        /// Initializes a new instance of the <see cref="FindOnly"/> class.
        /// </summary>
        /// <param name="_byteIntervalR">The _byte interval R.</param>
        /// <param name="_byteIntervalG">The _byte interval G.</param>
        /// <param name="_byteIntervalB">The _byte interval B.</param>
        public FindOnly(ByteInterval _byteIntervalR, ByteInterval _byteIntervalG, ByteInterval _byteIntervalB)
        {
            m_ByteIntervalR = _byteIntervalR;
            m_ByteIntervalG = _byteIntervalG;
            m_ByteIntervalB = _byteIntervalB;
        }

        /// <summary>
        /// Initializes a new instance of the <see cref="FindOnly"/> class.
        /// </summary>
        public FindOnly()
            : this(
            new List<Color>()
                {Color.Black, 
                Color.White}, 
            Color.Red)
        {
        }   

        /// <summary>
        /// constructor
        /// </summary>
        /// <param name="aColor"></param>
        /// <param name="colorToReplaceWith"></param>
        public FindOnly(IEnumerable<Color> aColor, Color colorToReplaceWith)
        {
            m_aColor = aColor;
            m_ColorToReplaceWith = colorToReplaceWith;
        }

        /// <summary>
        /// This is used by clone to create a deep copy
        /// </summary>
        /// <param name="_findOnly"></param>
        internal FindOnly(FindOnly _findOnly)
        {
            this.m_aColor = _findOnly.m_aColor;
            this.m_ByteIntervalR = _findOnly.m_ByteIntervalR;
            this.m_ByteIntervalG = _findOnly.m_ByteIntervalG;
            this.m_ByteIntervalB = _findOnly.m_ByteIntervalB;
            this.m_ColorToReplaceWith = _findOnly.m_ColorToReplaceWith;
        }

        /// <summary>
        /// Gets or sets R byte interval
        /// </summary>
        public ByteInterval R
        {
            get { return m_ByteIntervalR; }
            set { m_ByteIntervalR = value; }
        }

        /// <summary>
        /// Gets or sets G byte interval
        /// </summary>
        public ByteInterval G
        {
            get { return m_ByteIntervalG; }
            set { m_ByteIntervalG = value; }
        }

        /// <summary>
        /// Gets or sets B byte interval
        /// </summary>
        public ByteInterval B
        {
            get { return m_ByteIntervalB; }
            set { m_ByteIntervalB = value; }
        }

        /// <summary>
        /// Gets or sets the color list
        /// </summary>
        public IEnumerable<Color> ColorList
        {
            get { return m_aColor; }
            set { m_aColor = value; }
        }

        /// <summary>
        /// The color to replace with
        /// </summary>
        public Color ColorToReplaceWith
        {
            get { return m_ColorToReplaceWith; }
            set { m_ColorToReplaceWith = value; }
        }

        /// <summary>
        /// Executes this filter
        /// </summary>
        /// <param name="_bitmap"></param>
        public override UnsafeBitmap Execute(UnsafeBitmap _bitmap)
        {
            UnsafeBitmap bitmap = _bitmap;

            int nHeight = bitmap.Height;
            int nWidth = bitmap.Width;

            Color color = Color.Transparent;

            int y = 0;
            int x = 0;

            if (m_ByteIntervalR != null && m_ByteIntervalG != null && m_ByteIntervalB != null)
            {
                for (y = 0; y < nHeight; y++)
                {
                    for (x = 0; x < nWidth; x++)
                    {
                        color = bitmap.GetPixel(x, y);
                        if (m_ByteIntervalR.Contains(color.R) 
                            && m_ByteIntervalG.Contains(color.G) 
                            && m_ByteIntervalB.Contains(color.B))
                        {
                            bitmap.SetPixel(x, y, m_ColorToReplaceWith);
                        }
                    }
                }
            }
            else
            {
                for (y = 0; y < nHeight; y++)
                {
                    for (x = 0; x < nWidth; x++)
                    {
                        color = bitmap.GetPixel(x, y);
                        if (!m_aColor.Contains(color))
                        {
                            bitmap.SetPixel(x, y, m_ColorToReplaceWith);
                        }
                    }
                }
            }
            return _bitmap;
        }

        /// <summary>
        /// Use this to create a deep copy
        /// </summary>
        /// <returns></returns>
        public override object Clone()
        {
            return new FindOnly(this);
        }
    }
}
